IoC is a design principle where the control of object creation and dependency management is transferred to the Spring container instead of being managed manually in code.
Spring provides several types of IoC containers:
You can define a Spring Bean in an XML file as follows:
<bean id="myBean" class="com.example.MyClass"/>
Using Java-based configuration with @Configuration and @Bean:
@Configuration public class AppConfig { @Bean public MyClass myBean() { return new MyClass(); } }
Spring Bean scopes:
Using XML-based configuration:
<bean id="service" class="com.example.MyService"> <constructor-arg ref="repository"/> </bean>
Using Java-based configuration:
@Component public class MyService { private final MyRepository repository; @Autowired public MyService(MyRepository repository) { this.repository = repository; } }
Using XML configuration:
<context:component-scan base-package="com.example"/>
Using Java-based configuration:
@Configuration @ComponentScan("com.example") public class AppConfig {}
@Autowired is used to inject dependencies automatically. Example:
@Component public class MyService { @Autowired private MyRepository repository; }
Using @Primary annotation:
@Bean @Primary public MyRepository mainRepository() { return new MainRepositoryImpl(); }
Constructor injection is used when dependencies are passed via the constructor, while setter injection assigns dependencies via setter methods.
Example of constructor injection:
public class MyService { private final MyRepository repository; public MyService(MyRepository repository) { this.repository = repository; } }
Example of setter injection:
public class MyService { private MyRepository repository; public void setRepository(MyRepository repository) { this.repository = repository; } }
Using XML-based configuration:
<bean id="myService" class="com.example.MyService"> <constructor-arg ref="myRepository"/> </bean>
@Qualifier is used to specify which bean to inject when multiple beans of the same type exist.
@Component public class MyService { @Autowired @Qualifier("specialRepository") private MyRepository repository; }
A Spring Bean lifecycle includes creation, initialization, usage, and destruction.
Using XML configuration:
<bean id="myBean" class="com.example.MyClass" init-method="init" destroy-method="cleanup"/>
Using annotations:
public class MyClass { @PostConstruct public void init() { // Initialization logic } @PreDestroy public void cleanup() { // Cleanup logic } }
Spring can handle circular dependencies by using setter injection instead of constructor injection.
Lazy initialization delays bean creation until it is needed.
@Bean @Lazy public MyService myService() { return new MyService(); }
BeanFactory is a lower-level container, whereas ApplicationContext provides more features like event propagation and internationalization.
Using XML configuration:
<bean id="myBean" class="com.example.MyClass" scope="prototype"/>
Using Java configuration:
@Bean @Scope("prototype") public MyClass myBean() { return new MyClass(); }
Spring Profiles allow beans to be registered conditionally based on the environment.
@Profile("dev") @Bean public DataSource devDataSource() { return new HikariDataSource(); }
@Bean is used in Java-based configuration to explicitly declare a Spring bean, whereas @Component is used for automatic component scanning.
@Configuration public class AppConfig { @Bean public MyService myService() { return new MyService(); } }
Using Java-based configuration:
@Configuration @ComponentScan("com.example") public class AppConfig {}
@PostConstruct is used to execute initialization logic after dependency injection, and @PreDestroy is used for cleanup before a bean is destroyed.
public class MyBean { @PostConstruct public void init() { // Initialization logic } @PreDestroy public void cleanup() { // Cleanup logic } }
The default scope of a Spring bean is singleton.
You can create an ApplicationContext using:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Factory Beans are special beans that produce other beans dynamically.
public class MyFactoryBean implements FactoryBean{ @Override public MyBean getObject() throws Exception { return new MyBean(); } @Override public Class getObjectType() { return MyBean.class; } }
SpEL allows querying and manipulating objects dynamically in Spring.
@Value("#{systemProperties['user.name']}") private String userName;
Using @PropertySource:
@Configuration @PropertySource("classpath:app.properties") public class AppConfig {}
Using @Value annotation:
@Value("${app.name}") private String appName;
@DependsOn forces bean initialization order.
@Bean @DependsOn("otherBean") public MyBean myBean() { return new MyBean(); }
@Autowired is used for automatic dependency injection in Spring.
@Component public class MyService { @Autowired private MyRepository repository; }
Yes, @Autowired can be used on constructors for dependency injection.
@Component public class MyService { private final MyRepository repository; @Autowired public MyService(MyRepository repository) { this.repository = repository; } }
@Autowired is Spring-specific, while @Inject is a standard Java annotation from JSR-330.
@Autowired is Spring-specific, whereas @Resource is part of Java EE and allows specifying bean names.
Use @Qualifier to specify the exact bean.
@Component public class MyService { @Autowired @Qualifier("specialRepository") private MyRepository repository; }
Spring throws a NoSuchBeanDefinitionException unless @Autowired(required = false) is specified.
Use @Value to inject values from application.properties.
@Value("${app.name}") private String appName;
Singleton creates a single instance for the container, while prototype creates a new instance each time it is requested.
Use @ComponentScan in Java configuration.
@Configuration @ComponentScan("com.example") public class AppConfig {}
Use @Primary to mark a bean as the default when multiple beans exist.
@Bean @Primary public MyRepository defaultRepository() { return new DefaultRepository(); }
The default scope of a Spring bean is singleton.
Use @Scope("prototype") on the bean definition.
@Bean @Scope("prototype") public MyBean myPrototypeBean() { return new MyBean(); }
Yes, but it requires using ObjectFactory or Provider to get a new instance each time.
@Component public class SingletonBean { @Autowired private ObjectFactoryprototypeBeanFactory; public PrototypeBean getPrototypeInstance() { return prototypeBeanFactory.getObject(); } }
Field injection uses @Autowired on fields, while constructor injection provides better testability and immutability.
Use the name attribute in @Component or @Bean annotations.
@Component("myCustomBean") public class MyBean {}
@Lazy delays bean initialization until it is first requested.
@Bean @Lazy public ExpensiveBean expensiveBean() { return new ExpensiveBean(); }
Use ApplicationContext’s getBean() method.
MyBean myBean = applicationContext.getBean("myBean", MyBean.class);
@Configuration is used to define Java-based configuration for Spring beans.
Use @ComponentScan and @EnableAutoConfiguration.
@Configuration @ComponentScan("com.example") @EnableAutoConfiguration public class AppConfig {}
@DependsOn forces a bean to be initialized after another specified bean.
@Bean @DependsOn("otherBean") public MyBean myBean() { return new MyBean(); }
@Bean is used in Java-based configuration classes, while @Component is used for component scanning.
@Primary is used to indicate the primary bean when multiple beans of the same type exist.
@Bean @Primary public MyBean myPrimaryBean() { return new MyBean(); }
Use @Primary, @Qualifier, or manually retrieve beans from the context.
@PostConstruct is used for initialization logic, and @PreDestroy is used for cleanup.
@Component public class MyBean { @PostConstruct public void init() { System.out.println("Bean initialized"); } @PreDestroy public void destroy() { System.out.println("Bean destroyed"); } }
Use @PropertySource and Environment.
@Configuration @PropertySource("classpath:application.properties") public class AppConfig { @Autowired private Environment env; }
@Value is used to inject values from properties files.
@Value("${app.name}") private String appName;
Implement the Scope interface and register it with the ConfigurableBeanFactory.
By default, singleton beans are initialized in the order they are declared, but dependencies are resolved first.
A circular dependency occurs when two beans depend on each other. It can be resolved using @Lazy, constructor injection, or setter injection.
Use @Inject and @Named, and include the relevant dependency in the classpath.
@Named public class MyService {}
It allows modifying bean definitions before they are instantiated.
It replaces placeholders in bean definitions with values from property files.
@Resource is part of JSR-250 and allows specifying a bean name, whereas @Autowired is Spring-specific.
Use @PostConstruct, @PreDestroy, or define init-method and destroy-method in XML.
It ensures a bean is initialized only after specific dependent beans.
@Bean @DependsOn("dataSource") public MyService myService() { return new MyService(); }
It is used to register and scan Java-based configuration classes.
Prototype beans are created each time they are requested from the container.
It delays the initialization of a bean until it is requested.
Use a static factory method inside a configuration class.
@Bean public static MyBean createBean() { return new MyBean(); }
Use the @Conditional annotation with a custom condition class.
@Conditional allows defining conditions for bean creation, whereas @Profile enables environment-specific beans.
Implement the Condition interface and override the matches method.
public class MyCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return context.getEnvironment().containsProperty("my.property"); } }
By using lookup methods or ObjectFactory.
It provides lifecycle management methods for application contexts.
Use @ComponentScan in Java-based configurations.
@Configuration @ComponentScan("com.example") public class AppConfig {}
They allow beans to access ApplicationContext and BeanFactory, respectively.
Use @Import to import additional configuration classes.
It allows integrating Spring-managed beans with Servlet filters.
Singleton, Prototype, Request, Session, Application, and WebSocket.
FactoryBean creates objects dynamically, while a regular Bean is directly managed by the IoC container.
@Primary gives higher preference to a bean, whereas @Qualifier is used to specify a particular bean explicitly.
Use the registerBean method in ConfigurableApplicationContext.
context.registerBean(MyBean.class);
It is used to dynamically register bean definitions.
By using proxy beans or constructor injection with @Lazy.
It defines the scope of a bean, e.g., singleton, prototype.
Implement the BeanFactoryPostProcessor interface and override postProcessBeanFactory.
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // Modify bean definitions } }
ApplicationContext provides more features like event propagation and declarative bean creation.
It ensures that singleton beans are initialized after the complete bean creation process.
Use registerShutdownHook() on the application context.
context.registerShutdownHook();
By enabling component scanning and using @Inject instead of @Autowired.
It specifies that a bean should be initialized after another bean.
By calling the refresh() method on ConfigurableApplicationContext.
((ConfigurableApplicationContext) context).refresh();
It provides additional lifecycle methods such as refresh and close.
By using the @Lazy annotation.
@Bean @Lazy public MyBean myBean() { return new MyBean(); }
@PostConstruct is a JSR-250 annotation, whereas InitializingBean requires implementing an interface.
It enables method injection by dynamically returning a bean instance.
By using BeanDefinitionRegistry.
GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(MyBean.class); registry.registerBeanDefinition("myBean", beanDefinition);
It listens to application events published in the Spring context.
@EventListener public void handleEvent(MyEvent event) { System.out.println("Event received: " + event.getMessage()); }
By using MessageSource to load messages from properties files.
It enables support for handling components marked with @Aspect annotations.
It marks a bean as the primary candidate when multiple beans of the same type exist.
By using the @Scope("prototype") annotation.
@Bean @Scope("prototype") public MyBean myPrototypeBean() { return new MyBean(); }
ApplicationContext provides more features like event propagation, declarative mechanisms, and AOP support, whereas BeanFactory is a simpler container.
By using ConfigurableApplicationContext and BeanDefinitionRegistry.
GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(MyBean.class); registry.registerBeanDefinition("myBean", beanDefinition);
It allows bean creation based on specified conditions.
By using a setter method and marking it with @Autowired.
It enables Spring Boot to automatically configure components based on classpath dependencies.
By implementing ApplicationContextAware.
@Component public class MyBean implements ApplicationContextAware { private ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) { this.context = applicationContext; } }
@Service is a specialization of @Component, used for service layer beans.
By using @EnableAutoConfiguration(exclude = {SomeAutoConfiguration.class}).
It manages transactions automatically, ensuring consistency and rollback on failure.
Spring can resolve circular dependencies using proxies, but constructor-based dependencies may fail.
It defines a bean's scope to be limited to an HTTP session.
By using the @PostConstruct annotation or implementing InitializingBean.
A special bean that returns an instance of another object, not itself.
By implementing the Scope interface and registering it with ConfigurableBeanFactory.
@RestController is a combination of @Controller and @ResponseBody, used for REST APIs.
By using @CrossOrigin at the controller level or configuring WebMvcConfigurer.
It enables default Spring MVC configurations and components.
By using the @Value annotation.
@Value("${app.name}") private String appName;